package com.xiaoyu.base.view.list;

import android.content.Context;
import android.view.View;

import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import androidx.recyclerview.widget.StaggeredGridLayoutManager;

import in.srain.cube.views.list.CubeRecyclerViewAdapter;
import in.srain.cube.views.loadmore.LoadMoreContainer;
import in.srain.cube.views.loadmore.LoadMoreHandler;
import in.srain.cube.views.loadmore.LoadMoreUIHandler;

public class RecyclerViewLoadMoreController extends RecyclerView.OnScrollListener implements LoadMoreContainer {

    private int mFirstVisibleItem, mVisibleItemCount, mTotalItemCount;

    private LayoutManagerPositionProvider mPositionProvider;
    private int mVisibleThreshold = 0;
    private LoadMoreHandler mLoadMoreHandler;

    private boolean mIsLoading;
    private boolean mHasMore = false;
    private boolean mAutoLoadMore = true;
    private boolean mLoadError = false;
    private boolean mListEmpty = true;
    private boolean mShowLoadingForFirstPage = false;

    private LoadMoreUIHandler mLoadMoreUIHandler;
    private int mLoadMinTime = 0;

    private View mFooterView;

    public RecyclerViewLoadMoreController(Context context, CubeRecyclerViewAdapter adapter, LinearLayoutManager linearLayoutManager) {
        mPositionProvider = new LinearLayoutManagerPositionProvider(linearLayoutManager);
        init(context, adapter);
    }

    public RecyclerViewLoadMoreController(Context context, CubeRecyclerViewAdapter adapter, StaggeredGridLayoutManager staggeredGridLayoutManager) {
        mPositionProvider = new StaggeredGridLayoutManagerPositionProvider(staggeredGridLayoutManager);
        init(context, adapter);
    }

    private void init(Context context, CubeRecyclerViewAdapter adapter) {
        updateItemPositionData();

        LoadMoreFooterView footerView = new LoadMoreFooterView(context);
        if (mPositionProvider instanceof StaggeredGridLayoutManagerPositionProvider) {
            StaggeredGridLayoutManager.LayoutParams layoutParams = new StaggeredGridLayoutManager.LayoutParams(-2, -2);
            layoutParams.setFullSpan(true);
            footerView.setLayoutParams(layoutParams);
        }
        adapter.addFooterView(footerView);
        footerView.setVisibility(View.GONE);

        mFooterView = footerView;
        setLoadMoreView(footerView);
        setLoadMoreUIHandler(footerView);
    }

    public void setLoadMinTime(int loadMinTime) {
        mLoadMinTime = loadMinTime;
    }

    private void updateItemPositionData() {
        mTotalItemCount = mPositionProvider.getItemCount();
        mFirstVisibleItem = mPositionProvider.findFirstVisibleItemPosition();
    }

    @Override
    public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
        mVisibleItemCount = recyclerView.getChildCount();
        updateItemPositionData();

        if ((mTotalItemCount - mVisibleItemCount) <= (mFirstVisibleItem + mVisibleThreshold)) {
            onReachBottom();
        }
    }

    private void tryToPerformLoadMore() {
        if (mIsLoading) {
            return;
        }

        // no more content and also not load for first page
        if (!mHasMore && !(mListEmpty && mShowLoadingForFirstPage)) {
            return;
        }

        mIsLoading = true;

        if (mLoadMoreUIHandler != null) {
            mLoadMoreUIHandler.onLoading(this);
        }
        if (null != mLoadMoreHandler) {
            if (mLoadMinTime == 0) {
                mLoadMoreHandler.onLoadMore(this);
            } else {
                mFooterView.postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        mLoadMoreHandler.onLoadMore(RecyclerViewLoadMoreController.this);
                    }
                }, mLoadMinTime);
            }
        }
    }

    protected void onReachBottom() {
        // if has error, just leave what it should be
        if (mLoadError) {
            return;
        }
        if (mAutoLoadMore) {
            tryToPerformLoadMore();
        } else {
            if (mHasMore) {
                mLoadMoreUIHandler.onWaitToLoadMore(this);
            }
        }
    }

    @Override
    public void setShowLoadingForFirstPage(boolean showLoading) {
        mShowLoadingForFirstPage = showLoading;
    }

    @Override
    public void setAutoLoadMore(boolean autoLoadMore) {
        mAutoLoadMore = autoLoadMore;
    }

    @Override
    public void setLoadMoreView(View view) {
        mFooterView = view;
        view.setOnClickListener(v -> tryToPerformLoadMore());
    }

    @Override
    public void setLoadMoreUIHandler(LoadMoreUIHandler handler) {
        mLoadMoreUIHandler = handler;
    }

    @Override
    public void setLoadMoreHandler(LoadMoreHandler handler) {
        mLoadMoreHandler = handler;
    }

    /**
     * page has loaded
     *
     * @param emptyResult
     * @param hasMore
     */
    @Override
    public void loadMoreFinish(boolean emptyResult, boolean hasMore) {
        mLoadError = false;
        mListEmpty = emptyResult;
        mIsLoading = false;
        mHasMore = hasMore;

        if (mLoadMoreUIHandler != null) {
            mLoadMoreUIHandler.onLoadFinish(this, emptyResult, hasMore);
        }
    }

    @Override
    public void loadMoreError(int errorCode, String errorMessage) {
        mIsLoading = false;
        mLoadError = true;
        if (mLoadMoreUIHandler != null) {
            mLoadMoreUIHandler.onLoadError(this, errorCode, errorMessage);
        }
    }

    private interface LayoutManagerPositionProvider {
        int getItemCount();

        int findFirstVisibleItemPosition();
    }

    private static class LinearLayoutManagerPositionProvider implements LayoutManagerPositionProvider {

        private final LinearLayoutManager mLinearLayoutManager;

        private LinearLayoutManagerPositionProvider(LinearLayoutManager linearLayoutManager) {
            mLinearLayoutManager = linearLayoutManager;
        }

        @Override
        public int getItemCount() {
            return mLinearLayoutManager.getItemCount();
        }

        @Override
        public int findFirstVisibleItemPosition() {
            return mLinearLayoutManager.findFirstVisibleItemPosition();
        }
    }

    private static class StaggeredGridLayoutManagerPositionProvider implements LayoutManagerPositionProvider {

        private final StaggeredGridLayoutManager mStaggeredGridLayoutManager;

        private StaggeredGridLayoutManagerPositionProvider(StaggeredGridLayoutManager staggeredGridLayoutManager) {
            mStaggeredGridLayoutManager = staggeredGridLayoutManager;
        }

        @Override
        public int getItemCount() {
            return mStaggeredGridLayoutManager.getItemCount();
        }

        @Override
        public int findFirstVisibleItemPosition() {
            int[] posList = mStaggeredGridLayoutManager.findFirstVisibleItemPositions(null);
            int ret = Integer.MAX_VALUE;
            for (int i : posList) {
                ret = Math.min(i, ret);
            }
            return ret;
        }
    }
}
